//============================================================================
// Name        : client.c
// Author      : Jessica Brazelton & Eric Williams
// Course	   : CS 6210 Advanced Operating Systems
// Description :
//============================================================================

//================== HEADER FILES ==================
#include <xmlrpc-c/base.h>
#include <xmlrpc-c/client.h>
#include <stdlib.h>
#include <stdio.h>
#include <xmlrpc-c/config.h>  /* information about this build environment */

// =================== Symbolic Constants ========================
const int NUM_SERVICES = 3;
const char* METHOD_NAME = "flipCoin";
static volatile int sync = 0;

#define NAME "Xmlrpc-c Test Client"
#define VERSION "1.0"

enum{
	ANY=0,
	MAJORITY,
	ALL
} semantics;

enum {
	HEADS,
	TAILS
} toss;

long long totalResponseTime;
struct timeval current_time;
long long after, before;

int num_requests, heads, tails, error;

static void
dieIfFaultOccurred (xmlrpc_env * const envP) {
    if (envP->fault_occurred) {
        fprintf(stderr, "ERROR: %s (%d)\n",
                envP->fault_string, envP->fault_code);
        exit(1);
    }
}

static void
handle_sample_add_response(const char *   const serverUrl,
                           const char *   const methodName,
                           xmlrpc_value * const paramArrayP,
                           void *         const user_data,
                           xmlrpc_env *   const faultP,
                           xmlrpc_value * const resultP) {

    xmlrpc_env env;
    xmlrpc_int addend, adder;

    /* Initialize our error environment variable */
    xmlrpc_env_init(&env);

    /* Our first four arguments provide helpful context.  Let's grab the
       addends from our parameter array.
    */
    xmlrpc_decompose_value(&env, paramArrayP, "(ii)", &addend, &adder);
    dieIfFaultOccurred(&env);
   // carrier* my_carrier = (carrier*) user_data;
    //printf("%ld", (long int)user_data);
     //printf("RPC #%ld with method '%s' at URL '%s' has completed\n",(long int)user_data, methodName, serverUrl);

    //printf("RPC with method '%s' at URL '%s' to add %d and %d "
      //     "has completed\n", methodName, serverUrl, addend, adder);

    if (faultP->fault_occurred)
        printf("The RPC failed.  %s\n", faultP->fault_string);
    else
    {
        xmlrpc_int result;

        xmlrpc_read_int(&env, resultP, &result);
        dieIfFaultOccurred(&env);

        //printf("The sum is  %d\n", sum);
        sync = 1;

        if(result == 0)
        {
        	heads++;
        }
        else if(result == 1)
        {
            					tails++;
        }
        else
        {
            					error++;
        }
    }

    gettimeofday(&current_time,NULL);
    after = ((current_time.tv_sec * 1000) + ((current_time.tv_usec)/1000));
    totalResponseTime += (after - before);


}

int main(int size, char* param[]) {
	//int num_requests, heads, tails, error;
	//long long totalResponseTime;
	double avg_response;
	int j, k;
	xmlrpc_env env;
	xmlrpc_value* resultP;
    xmlrpc_int32 result;
    char* url = "http://localhost:8080/RPC2";
    //struct timeval current_time;
    //long long after, before;

    if (size - 1 != 1) {
    	printf("You must specify the number of requests\n");
    	exit(1);
    }

    /* Initialize our error-handling environment. */
    xmlrpc_env_init(&env);

    xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0);
    dieIfFaultOccurred(&env);
    num_requests = atoi(param[1]);
    int iter;
    int s, r;

    for(iter = 0; iter < 2; ++iter) {
    	if(iter == 0) {
    		//Sync calls, iterate through the different semantics, any,all, majority
    		for(s = 0; s < 3; ++s) {
    			heads = 0;
    			tails = 0;
    			error = 0;
    			totalResponseTime = 0;

    			for(r = 0; r < num_requests; r++)
    			{
    				gettimeofday(&current_time,NULL);
    				before = ((current_time.tv_sec * 1000) + ((current_time.tv_usec)/1000));

    				/* Make the remote procedure call */

    				if(s>2||s<0)
    					printf("Error with semantic\n");
    				resultP = multirpc_client_call(s,  //0 - Any, 1 - Majority, 2 - all
    												3,
    												&env,
    												url,
    												METHOD_NAME,
    												"(ii)");

    				dieIfFaultOccurred(&env);

    				/* Get our result and print it out. */
    				xmlrpc_read_int(&env, resultP, &result);
    				dieIfFaultOccurred(&env);

    				gettimeofday(&current_time,NULL);
    				after = ((current_time.tv_sec * 1000) + ((current_time.tv_usec)/1000));
    				totalResponseTime += (after - before);

    				if(result == 0) {
    					heads++;
    				} else if(result == 1) {
    					tails++;
    				} else {
    					error++;
    				}

    				//xmlrpc_DECREF(resultP); 	// Dispose of our result value.

    			} // end for each request

    		    avg_response = ((double)totalResponseTime) / (num_requests);

    		    // print results
    		    printf("%d|%d|%d|%d|%d|%lf\n", s, heads, tails, error, iter, avg_response);

    		} // end for each semantic
    	}
    	else
    	{
    		// Async calls, iterate through the different semantics, any, all, majority
    		for(s = 0; s < 3; ++s) {
    			totalResponseTime = 0;
    			heads = 0;
    			tails = 0;
    			error = 0;

    			for(r = 0; r < num_requests; r++) {
    				/* Initialize our error environment variable */
    				//xmlrpc_env_init(&env);

    				/* Start up our XML-RPC client library. */
    				//xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0);
    				//dieIfFaultOccurred(&env);

					gettimeofday(&current_time,NULL);
					before = ((current_time.tv_sec * 1000) + ((current_time.tv_usec)/1000));

					/* Make the remote procedure call */
					multirpc_client_async_call(s,  //0 - Any, 1 - Majority, 2 - all
															3,
							        						url,
							        						METHOD_NAME,
							        						handle_sample_add_response,
							        					    (void*)r,
							        					    "(ii)");

					dieIfFaultOccurred(&env);

					/* Get our result and print it out. */
					xmlrpc_read_int(&env, resultP, &result);
					dieIfFaultOccurred(&env);

					//gettimeofday(&current_time,NULL);
					//after = ((current_time.tv_sec * 1000) + ((current_time.tv_usec)/1000));
					//totalResponseTime += (after - before);
    			} // end for each request

    			xmlrpc_client_event_loop_finish_asynch();
    			avg_response = ((double)totalResponseTime) / (num_requests);

    			 //print results
    			printf("%d|%d|%d|%d|%d|%3.1lf\n", s, heads, tails, error, iter, avg_response);


    		} // end for each semantic
    	} // end if async
    }

    xmlrpc_DECREF(resultP); 	// Dispose of our result value.
    xmlrpc_env_clean(&env); 	// Clean up our error-handling environment.
    xmlrpc_client_cleanup();	// Shutdown our XML-RPC client library.
//    for(j = 0; j < num_requests; j++) {
//    	printf("R%d: ", j);
//
//    	/* Start up our XML-RPC client library. */
//    	xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0);
//    	dieIfFaultOccurred(&env);
//
//
//    	//====================== MAJORITY ======================
//    	gettimeofday(&current_time,NULL);
//    	before = ((current_time.tv_sec * 1000) + ((current_time.tv_usec)/1000));
//
//    	/* Make the remote procedure call */
//    	resultP = multirpc_client_call(ALL,  //0 - Any, 1 - Majority, 2 - all
//    									3,
//    									&env,
//    									url,
//    									METHOD_NAME,
//    									"(ii)");
//
//    	dieIfFaultOccurred(&env);
//
//    	/* Get our result and print it out. */
//    	xmlrpc_read_int(&env, resultP, &result);
//    	dieIfFaultOccurred(&env);
//
//    	gettimeofday(&current_time,NULL);
//    	after = ((current_time.tv_sec * 1000) + ((current_time.tv_usec)/1000));
//    	totalResponseTime += (after - before);
//
//    	printf("%d | ", result);
//    	xmlrpc_DECREF(resultP); 	// Dispose of our result value.
//    	xmlrpc_client_cleanup();	// Shutdown our XML-RPC client library.
//		printf("\n");
//    }
//
//    avg_response = ((double)totalResponseTime) / (num_requests);
//    printf("Average Response Time: %lf ms\n", avg_response);
//    xmlrpc_env_clean(&env); 	// Clean up our error-handling environment.

	return 0;
} // end main
